import { ECSComp } from "./ECSComp";
import { ECSEntity } from "./ECSEntity";
import { ECSMatcher } from "./ECSMatcher";
import { CompCtor, CompType, ECSModel, EntityCtor } from "./ECSModel";
import { ECSComblockSystem, ECSRootSystem, ECSSystem } from "./ECSSystem";
import { Log } from "../logger/LoggerGlobal";

/** 
 * ECSEntity对象在destroy后，会回收到ECSModel.entityPool实体对象池中
 * ECSComp对象从ECSEntity.remove后，数据组件会回收到ECSModel.compPools组件对象池中
 */

/** 
 * Entity-Component-System（实体-组件-系统）框架
 * 文档：https://gitee.com/dgflash/oops-framework/wikis/pages?sort_id=12033388&doc_id=2873565
 */
export namespace ecs {
    /** 实体 - 一个概念上的定义，指的是游戏世界中的一个独特物体，是一系列组件的集合 */
    export type Entity = ECSEntity;
    /** 组件 - 一堆数据的集合，即不存在任何的行为，只用来存储状态 */
    export type Comp = ECSComp;
    /** 系统 - 关注实体上组件数据变化，处理游戏逻辑 */
    export type System = ECSSystem;
    /** 根系统 - 驱动游戏中所有系统工作 */
    export type RootSystem = ECSRootSystem;
    /** 处理游戏逻辑系统对象 - 继承此对象实现自定义业务逻辑 */
    export type ComblockSystem = ECSComblockSystem;

    /** 实体 - 一个概念上的定义，指的是游戏世界中的一个独特物体，是一系列组件的集合 */
    export const Entity = ECSEntity;
    /** 组件 - 一堆数据的集合，即不存在任何的行为，只用来存储状态 */
    export const Comp = ECSComp;
    /** 系统 - 关注实体上组件数据变化，处理游戏逻辑 */
    export const System = ECSSystem;
    /** 根系统 - 驱动游戏中所有系统工作 */
    export const RootSystem = ECSRootSystem;
    /** 处理游戏逻辑系统对象 - 继承此对象实现自定义业务逻辑 */
    export const ComblockSystem = ECSComblockSystem;

    //#region 接口

    /** 组件接口 */
    export interface IComp {
        canRecycle: boolean;
        ent: Entity;
        tid: number;

        reset(): void;
    }

    /** 实体匹配器接口 */
    export interface IMatcher {
        mid: number;
        indices: number[];
        key: string;
        isMatch(entity: Entity): boolean;
    }

    /**
     * 监听组件首次添加到实体上时，在ComblockSystem上实现这个接口
     * 1. entityEnter会在update方法之前执行，实体进入后，不会再次进入entityEnter方法中
     * 2. 当实体从当前System移除，下次再次符合条件进入System也会执行上述流程
     * @example
    export class RoleUpgradeSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {
        filter(): ecs.IMatcher {
            return ecs.allOf(RoleUpgradeComp, RoleModelLevelComp);
        }

        entityEnter(e: Role): void {
            e.remove(RoleUpgradeComp);
        }
    }
     */
    export interface IEntityEnterSystem<E extends Entity = Entity> {
        entityEnter(entity: E): void;
    }

    /** 监听组件从实体上移除时，在ComblockSystem上实现这个接口 */
    export interface IEntityRemoveSystem<E extends Entity = Entity> {
        entityRemove(entity: E): void;
    }

    /** 监听系统第一次执行update处理实体时，在ComblockSystem上实现这个接口 */
    export interface ISystemFirstUpdate<E extends Entity = Entity> {
        firstUpdate(entity: E): void;
    }

    /** 监听系统执行update处理实体时，在ComblockSystem上实现这个接口 */
    export interface ISystemUpdate<E extends Entity = Entity> {
        update(entity: E): void;
    }

    /** 系统执行前钩子 - 在遍历实体之前调用 */
    export interface ISystemBeforeExecute {
        beforeExecute(dt: number): void;
    }

    /** 系统执行后钩子 - 在遍历实体之后调用 */
    export interface ISystemAfterExecute {
        afterExecute(dt: number): void;
    }
    //#endregion

    /**
     * 注册组件到ecs系统中
     * @param name   由于js打包会改变类名，所以这里必须手动传入组件的名称
     * @param canNew 标识是否可以new对象。想继承自Cocos Creator的组件就不能去new，需要写成@ecs.register('name', false)
     * @example
    // 注册实体
    @ecs.register('Role')
    export class Role extends ecs.Entity {

    }

    // 注册数据组件
    @ecs.register('RoleModel')
    export class RoleModelComp extends ecs.Comp {
        id: number = -1;

        reset() {
            this.id =  -1;
        }
    }

    // 注册系统组件
    @ecs.register('Initialize')
    export class InitResSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem {

    }

    // 注册显示对象组件
    @ccclass('RoleViewComp')
    @ecs.register('RoleView', false)
    export class RoleViewComp extends CCComp {
        onLoad(){
            
        }
    }
    */
    export function register<T>(name: string, canNew: boolean = true) {
        return function (ctor: any) {
            // 注册系统
            if (ctor.s) {
                let system = ECSModel.systems.get(name);
                if (!system) {
                    system = new ecs.System();
                    ECSModel.systems.set(name, system);
                }
                system.add(new ctor());
                return;
            }
            
            // 注册实体
            if (ctor.tid === undefined) {
                ECSModel.entityCtors.set(ctor as EntityCtor<T>, name);
                return;
            }
            
            // 注册组件
            // 修复：支持组件继承
            // 检查当前类是否已经有自己的 tid（不是继承的）
            const hasOwnTid = Object.prototype.hasOwnProperty.call(ctor, 'tid');
            
            if (!hasOwnTid || ctor.tid === -1) {
                // 为当前类分配新的 tid
                ctor.tid = ECSModel.compTid++;
                ctor.compName = name;
                ECSModel.compCtors.push(ctor);
                if (canNew) {
                    ECSModel.compPools.set(ctor.tid, []);
                }
                ECSModel.compAddOrRemove.set(ctor.tid, []);
            } else {
                // 真正的重复注册（同一个类注册两次）
                throw new Error(
                    `ECS 组件重复注册: ${name}\n` +
                    `tid: ${ctor.tid}\n` +
                    `compName: ${ctor.compName || 'unknown'}`
                );
            }
        }
    }

    /**
     * 创建一个新的实体对象或从缓存中获取一个实体对象
     * @param ctor 实体类
     */
    export function getEntity<T extends Entity>(ctor: EntityCtor<T>): T {
        // 获取实体对象名
        const entityName = ECSModel.entityCtors.get(ctor);
        if (!entityName) {
            throw new Error(`${ctor.name} 实体没有注册，请使用 @ecs.register 装饰器注册`);
        }

        // 获取实体对象池
        const pool = ECSModel.getEntityPool(entityName);
        let entity = pool.pop() as T | undefined;

        // 缓存中没有同类实体，则创建一个新的
        if (!entity) {
            entity = new ctor();
            (entity as any).eid = ECSModel.eid++;
            (entity as any).name = entityName;
        }

        // 触发实体初始化逻辑
        const entityAny = entity as any;
        if (typeof entityAny.init === 'function') {
            entityAny.isValid = true;
            entityAny.init();
        } else {
            throw new Error(`${ctor.name} 实体缺少 init 方法初始化默认组件`);
        }

        ECSModel.eid2Entity.set(entityAny.eid, entity);
        return entity;
    }

    /**
     * 动态查询实体
     * @param matcher 匹配器
     * @example
     * ecs.query(ecs.allOf(Comp1, Comp2));
     */
    export function query<E extends Entity = Entity>(matcher: IMatcher): E[] {
        let group = ECSModel.groups.get(matcher.mid);
        if (!group) {
            group = ECSModel.createGroup(matcher);
            // 使用传统 for 循环遍历所有实体，性能更好
            const entities = ECSModel.eid2Entity.values();
            for (const entity of entities) {
                group.onComponentAddOrRemove(entity);
            }
        }
        return group.matchEntities as E[];
    }

    /** 清理所有的实体 */
    export function clear() {
        // 优化：先清理实体，避免重复触发事件
        if (ECSModel.eid2Entity.size > 0) {
            const entities = Array.from(ECSModel.eid2Entity.values());
            const len = entities.length;
            for (let i = 0; i < len; i++) {
                entities[i].destroy();
            }
            ECSModel.eid2Entity.clear();
        }

        // 清理所有组
        if (ECSModel.groups.size > 0) {
            for (const group of ECSModel.groups.values()) {
                group.clear();
            }
            ECSModel.groups.clear();
        }

        // 清理所有组件监听器
        if (ECSModel.compAddOrRemove.size > 0) {
            for (const callbackLst of ECSModel.compAddOrRemove.values()) {
                callbackLst.length = 0;
            }
        }
    }

    /**
     * 通过实体唯一编号获得实体对象
     * @param eid 实体唯一编号
     */
    export function getEntityByEid<E extends Entity = Entity>(eid: number): E | undefined {
        return ECSModel.eid2Entity.get(eid) as E | undefined;
    }

    /**
     * 检查实体是否存在
     * @param eid 实体唯一编号
     */
    export function hasEntity(eid: number): boolean {
        return ECSModel.eid2Entity.has(eid);
    }

    /** 当前活动中的实体数量 */
    export function activeEntityCount(): number {
        return ECSModel.eid2Entity.size;
    }

    /**
     * 获取所有活动实体
     * @returns 所有活动实体的数组
     */
    export function getAllEntities<E extends Entity = Entity>(): E[] {
        const result: E[] = [];
        result.length = ECSModel.eid2Entity.size;
        let i = 0;
        for (const entity of ECSModel.eid2Entity.values()) {
            result[i++] = entity as E;
        }
        return result;
    }

    /** 创建实体 */
    function createEntity<E extends Entity = Entity>(): E {
        const entity = new Entity();
        entity.eid = ECSModel.eid++;
        ECSModel.eid2Entity.set(entity.eid, entity);
        return entity as E;
    }

    /**
     * 指定一个组件创建实体，返回组件对象。
     * @param ctor 组件构造函数
     */
    function createEntityWithComp<T extends IComp>(ctor: CompCtor<T>): T {
        const entity = createEntity();
        return entity.add(ctor);
    }

    //#region 过滤器
    /**
     * 表示只关心这些组件的添加和删除动作。虽然实体可能有这些组件之外的组件，但是它们的添加和删除没有被关注，所以不会存在对关注之外的组件
     * 进行添加操作引发Group重复添加实体。
     * @param args 组件类型数组
     * @example
     * ecs.allOf(AComponent, BComponent, CComponent);
     */
    export function allOf(...args: CompType<IComp>[]): ECSMatcher {
        return new ECSMatcher().allOf(...args);
    }

    /**
     * 组件间是或的关系，表示关注拥有任意一个这些组件的实体
     * @param args 组件类
     * @example
     * ecs.anyOf(AComponent, BComponent);
     */
    export function anyOf(...args: CompType<IComp>[]): ECSMatcher {
        return new ECSMatcher().anyOf(...args);
    }

    /**
     * 表示关注只拥有这些组件的实体
     * 注：不是特殊情况不建议使用onlyOf。因为onlyOf会监听所有组件的添加和删除事件
     * @param args 组件类
     * @example
     // 不包含CComponent或者DComponent
     ecs.allOf(AComponent, BComponent).excludeOf(CComponent, DComponent);

     // 不同时包含CComponent和DComponent
     ecs.allOf(AComponent, BComponent).excludeOf(CComponent).excludeOf(DComponent);
     */
    export function onlyOf(...args: CompType<IComp>[]): ECSMatcher {
        return new ECSMatcher().onlyOf(...args);
    }

    /**
     * 不包含指定的任意一个组件
     * @param args 组件类
     * @example
     // 表示不包含组件A或者组件B
     ecs.excludeOf(A, B); 
     */
    export function excludeOf(...args: CompType<IComp>[]): ECSMatcher {
        return new ECSMatcher().excludeOf(...args);
    }
    //#endregion

    //#region 单例组件
    /**
     * 获取单例组件
     * @param ctor 组件类
     */
    export function getSingleton<T extends IComp>(ctor: CompCtor<T>): T {
        let comp = ECSModel.tid2comp.get(ctor.tid) as T | undefined;
        if (!comp) {
            comp = createEntityWithComp(ctor) as T;
            ECSModel.tid2comp.set(ctor.tid, comp);
        }
        return comp;
    }

    /**
     * 检查单例组件是否存在
     * @param ctor 组件类
     */
    export function hasSingleton<T extends IComp>(ctor: CompCtor<T>): boolean {
        return ECSModel.tid2comp.has(ctor.tid);
    }

    /**
     * 注册单例组件 - 主要用于那些不能手动创建对象的组件
     * @param obj 组件实例
     */
    export function addSingleton(obj: IComp): void {
        const tid = (obj.constructor as CompCtor<IComp>).tid;
        if (!ECSModel.tid2comp.has(tid)) {
            ECSModel.tid2comp.set(tid, obj);
        }
    }

    /**
     * 移除单例组件
     * @param ctor 组件类
     */
    export function removeSingleton<T extends IComp>(ctor: CompCtor<T>): boolean {
        return ECSModel.tid2comp.delete(ctor.tid);
    }

    //#endregion

    //#region 性能监控和调试工具
    /**
     * 获取 ECS 系统统计信息
     */
    export function getStatistics() {
        return ECSModel.getStatistics();
    }

    /**
     * 打印 ECS 系统统计信息到控制台
     */
    export function printStatistics(): void {
        ECSModel.printStatistics();
    }

    /**
     * 预热实体池
     * @param ctor 实体构造函数
     * @param count 预分配数量
     */
    export function warmupEntityPool<T extends Entity>(ctor: EntityCtor<T>, count: number): void {
        const entityName = ECSModel.entityCtors.get(ctor);
        if (!entityName) {
            Log.ecs.warn('实体未注册，无法预热池', { entityName: ctor.name });
            return;
        }
        
        // 创建临时实体进行预热
        for (let i = 0; i < count; i++) {
            const tempEntity = new ctor();
            const pool = ECSModel.getEntityPool(entityName);
            pool.push(tempEntity as any);
        }
    }

    /**
     * 预热组件池
     * @param ctor 组件构造函数
     * @param count 预分配数量
     */
    export function warmupComponentPool<T extends IComp>(ctor: CompCtor<T>, count: number): void {
        const pool = ECSModel.getCompPool(ctor.tid);
        if (!pool) {
            Log.ecs.warn('组件没有对象池，可能是 canNew=false', { tid: ctor.tid });
            return;
        }

        // 创建临时组件进行预热
        for (let i = 0; i < count; i++) {
            const tempComp = new ctor();
            pool.push(tempComp as any);
        }
    }

    /**
     * 清空所有对象池（保留注册信息）
     */
    export function clearAllPools(): void {
        ECSModel.clearAllPools();
    }

    /**
     * 重置整个 ECS 系统（危险操作，会清除所有数据）
     */
    export function reset(): void {
        ECSModel.reset();
    }

    //#endregion
}